/*
@(#)WechatPaymentController   2024-09-23
 
Copyright (c) 2011-2024 杭州湖畔网络技术有限公司 
保留所有权利 
本软件为杭州湖畔网络技术有限公司所有及包含机密信息，须遵守其相关许可证条款进行使用。
Copyright (c) 2011-2024 HUPUN Network Technology CO.,LTD.
All rights reserved.
This software is the confidential and proprietary information of HUPUN
Network Technology CO.,LTD("Confidential Information").  You shall not
disclose such Confidential Information and shall use it only in
accordance with the terms of the license agreement you entered into with HUPUN.
Website：http://www.hupun.com
*/
package org.obp.pay.third.wechat.callback;

import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.obp.pay.pool.PaymentPoolManager;
import org.obp.pay.service.PaymentCallbackService;
import org.obp.pay.third.wechat.config.WechatpayConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: Jackey 2024/9/23
 */
@Slf4j
@Controller
@RequestMapping("/v1/payment")
@Api(tags = {"微信支付回调接口"})
public class WechatpayCallback {

    @Autowired
    private WechatpayConfig wechatpayConfig;
    @Autowired
    private PaymentPoolManager paymentPoolManager;
    @Autowired
    private PaymentCallbackService paymentCallbackService;

    @ResponseBody
    @ApiOperation("微信支付结果异步通知")
    @PostMapping(value = "/pay/notify/wechatpay", consumes = MediaType.ALL_VALUE)
    public String asyncPayNotifyWechatPay(HttpServletRequest request) {

        try {
            String requestBody = this.getRequestBody(request);
            log.info("微信支付回调信息: " + requestBody);

            String signature = request.getHeader("Wechatpay-Signature");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String serial = request.getHeader("Wechatpay-Serial");
            String signType = request.getHeader("Wechatpay-Signature-Type");

            // 构造 RequestParam
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(serial)
                    .nonce(nonce)
                    .signature(signature)
                    .timestamp(timestamp)
                    .signType(signType)
                    .body(requestBody)
                    .build();

            // 初始化 NotificationParser
            NotificationParser parser = new NotificationParser(wechatpayConfig.getWxPayConfig());

            // 以支付通知回调为例，验签、解密并转换成 Transaction
            log.info("微信支付回调验签参数: {}", requestParam);

            Transaction transaction = parser.parse(requestParam, Transaction.class);
            log.info("微信支付回调信息解密后: {}", transaction.toString());

            if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {

                log.info("订单号: {}, 微信支付订单号: {} 未支付成功", transaction.getOutTradeNo(), transaction.getTransactionId());

                Map<String, String> returnMap = new HashMap<>(2);
                returnMap.put("code", "FAIL");
                returnMap.put("message", "失败");
                return JSONObject.toJSONString(returnMap);
            }

            paymentPoolManager.submit(() -> paymentCallbackService.wechatPayCallback(transaction));

        } catch (Exception e) {

            log.error("payment callback failed e: ", e);
        }

        Map<String, String> returnMap = new HashMap<>(2);
        returnMap.put("code", "SUCCESS");
        returnMap.put("message", "成功");
        return JSONObject.toJSONString(returnMap);
    }

    @ResponseBody
    @ApiOperation("微信退款结果异步通知")
    @PostMapping(value = "/refund/notify/wechatpay", consumes = MediaType.ALL_VALUE)
    public String asyncRefundNotifyWechatPay(HttpServletRequest request) {

        try {
            String requestBody = this.getRequestBody(request);
            log.info("微信支付退款回调信息: " + requestBody);

            String signature = request.getHeader("Wechatpay-Signature");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String serial = request.getHeader("Wechatpay-Serial");
            String signType = request.getHeader("Wechatpay-Signature-Type");

            // 构造 RequestParam
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(serial)
                    .nonce(nonce)
                    .signature(signature)
                    .timestamp(timestamp)
                    .signType(signType)
                    .body(requestBody)
                    .build();

            // 初始化 NotificationParser
            NotificationParser parser = new NotificationParser(wechatpayConfig.getWxPayConfig());

            // 以支付通知回调为例，验签、解密并转换成 Transaction
            log.info("微信支付退款回调验签参数: {}", requestParam);

            RefundNotification refundNotification = parser.parse(requestParam, RefundNotification.class);
            log.info("微信支付退款回调信息解密后: {}", refundNotification.toString());

            paymentPoolManager.submit(() -> paymentCallbackService.wechatRefundCallback(refundNotification));

        } catch (Exception e) {

            log.error("payment callback failed e: ", e);
        }

        Map<String, String> returnMap = new HashMap<>(2);
        returnMap.put("code", "SUCCESS");
        returnMap.put("message", "成功");
        return JSONObject.toJSONString(returnMap);
    }


    /**
     * 获取请求体
     *
     * @param request
     * @return
     * @throws IOException
     */
    private String getRequestBody(HttpServletRequest request) throws IOException {
        ServletInputStream stream;
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        try {
            stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            throw new IOException("读取返回支付接口数据流出现异常！");
        } finally {
            reader.close();
        }
        return sb.toString();
    }

}